'''

@author: noako
'''

from math import pi
from GeometryHelper import Bisector, AngleBetween 
from heapq import heappush
from Events import EdgeEvent, SplitEvent


def CreateSLAV(polygon_edge, event_queue):
    # We create a list of LAV nodes, in CCW order, associated with vertices
    # The list is not saved anywhere, it is just useful for initialization
    # The result will be a linked list of LAV nodes.
    # The appropriate events will be saved in the event queue, with pointers to the relevant LAV nodes.
    
    nodes = [LAVNode(polygon_edge.origin)]
    current_edge = polygon_edge.next
    while (current_edge != polygon_edge):
        nodes.append(LAVNode(current_edge.origin))
        current_edge = current_edge.next
    
    # connect each LAV node with the two adjacent LAV nodes
    for i, node in enumerate(nodes):
        node.left = nodes[i - 1]
        nodes[i - 1].right = node
    
    # connect each LAV node with the right and left edges
    current_edge = polygon_edge.prev
    for i, node in enumerate(nodes):
        node.left_edge = current_edge
        nodes[i - 1].right_edge = current_edge
        current_edge = current_edge.next
    
    # compute bisectors
    for node in nodes:
        node.ComputeBisector()
    
    # compute edge and split events and add them to the queue
    # For simplicity, we add all possible events, rather than finding the closest event to a
    # certain node and only adding those events. This will at most add 3 events per node:
    # two possible edge events, and one possible split event. At most one split event is feasible
    # because we also check that the split location is within the correct bisector bounds
    for node in nodes:
        edge_event = EdgeEvent(node, node.right)
        if edge_event != None:
            heappush(event_queue, edge_event)
        
        if IsReflexVertex(node):
            opposing_edge_left_node = node.right.right
            while opposing_edge_left_node.right != node.left:
                split_event = SplitEvent(node, opposing_edge_left_node)
                if split_event != None:
                    heappush(event_queue, split_event)
                opposing_edge_left_node = opposing_edge_left_node.right
    
class LAVNode:
    def __init__(self, vertex):
        self.vertex = vertex
        self.active = True
        self.bisector = None
        # The concept of right\left is when you're "standing" on the vertex and looking *into* the polygon
        self.right = None  # neighboring LAVNode on the right
        self.left = None  # neighboring LAVNode on the left
        self.right_edge = None
        self.left_edge = None
        
    def ComputeBisector(self, time = 0):
        assert(self.right_edge is not None and self.left_edge is not None)
        self.bisector = Bisector(self.right_edge, self.left_edge, self.vertex, time)

    def __repr__(self):
        return str(self.vertex)
            
def ConnectLAVNodes(left, middle, right):
    left.right = middle
    middle.left = left
    middle.right = right
    right.left = middle

def IsReflexVertex(node):
    if node.right_edge.angle() > 0:
        a3 = node.right_edge.angle() - pi
    else:
        a3 = node.right_edge.angle() + pi
    return not AngleBetween(node.right_edge.angle(), node.left_edge.twin.angle(), a3)
